using System;
using System.IO;
using System.Threading;
using System.Text;
using System.Net;
using System.Collections.Generic;
using Sce.PlayStation.Core;
using Sce.PlayStation.Core.Environment;
using Sce.PlayStation.HighLevel.UI;
using VitaReader;

namespace VitaReaderLibPS
{
	internal class DownloadState
	{
		private FileStream 		mOStream = null;	//disk write
		private Stream			mNetStream = null;
		private StreamReader	mNetReader = null;	//transfer stream
		private WebRequest		mFileReq = null;
		private WebResponse		mFileResp = null;
		private bool			mDownloading = false;
		private long			mSaved;
		
		public FileStream 	OStream 	{get {return mOStream;} set {mOStream = value;}}
		public Stream		NetStream	{get {return mNetStream;} set {mNetStream = value;}}
		public StreamReader	NetReader	{get {return mNetReader;} set {mNetReader = value;}}
		public WebRequest	Request		{get {return mFileReq;}	set {mFileReq = value;}}
		public WebResponse	Response	{get {return mFileResp;} set {mFileResp = value;}}
		public bool			Downloading	{get {return mDownloading;}}
		
		public void	Close()
		{		
			if(mOStream != null )
			{
				mOStream.Close();
				mOStream = null;
			}
			if(mNetStream != null )
			{
				mNetStream.Close();
				mNetStream = null;
			}
			if( mNetReader != null )
			{
				mNetReader.Close();
				mNetReader = null;
			}
			if( mFileResp != null )
			{
				mFileResp.Close();
				mFileResp = null;
			}			
			if( mFileReq != null )
			{
				mFileReq.Abort();
				mFileReq = null;
			}
			
			mDownloading = false;
			mSaved = 0;
		}
		
		public void Open(String URL, String Path)
		{
			this.Close();
			
			
			try
			{
				this.Request = WebRequest.Create(URL);
				this.Response = this.Request.GetResponse();
				this.NetStream = this.Response.GetResponseStream();
				this.NetReader = new StreamReader(this.NetStream, Encoding.Unicode);
				this.OStream = new FileStream(Path, FileMode.Create);
				mDownloading = true;
			}
			catch(Exception e)
			{
				this.Close();
				//Console.WriteLine(e.Message);
			}
		}
		
		public float Continue(int bytes)
		{
			//Console.WriteLine("FUCK!");
			//Console.WriteLine(mDownloading);
			byte[] cache = new byte[bytes];
			int transferred = this.NetStream.Read(cache, 0, bytes);
			mSaved += (long)transferred;
			this.OStream.Write(cache, 0, transferred);
			
			if( this.mSaved == this.Response.ContentLength )	//finish
			{
				this.Close();
				return 1.0f;
			}
			return (float)mSaved/(float)this.Response.ContentLength;
		}
	}
	
	internal class  Network
	{
		String			mScheme;
		DownloadState	mDownloadState;
		bool			mValidConnetion;
		
		private int		mDownloadIndex;
		
		public Network()
		{
			mDownloadState = new DownloadState();
		}
		
		//TODO: network function
		public bool			TestConnection(String URL)
		{
			//debug
			/*
			{
				mScheme = Uri.UriSchemeHttp;
				mValidConnetion = true;
				return true;
			}
			*/
			mValidConnetion = false;
			try
			{
				Uri uri = new Uri(URL);
				mScheme = uri.Scheme;
				if( mScheme == Uri.UriSchemeFtp )
				{
					WebRequest req = WebRequest.Create(uri);
					req.Method = WebRequestMethods.Ftp.ListDirectory;
					// Get the response instance.
	            	WebResponse resp = req.GetResponse();
					mValidConnetion = (resp.ContentLength > 0);
					resp.Close();
					req.Abort();
				}
				else if( mScheme == Uri.UriSchemeHttp )
				{
					HttpWebRequest req = (HttpWebRequest)WebRequest.Create(uri);
					//req.Method = WebRequestMethods.Http.Connect;
					//req.KeepAlive = true;
					// Get the response instance.
	            	HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
					mValidConnetion = (resp.StatusCode == System.Net.HttpStatusCode.OK);
					resp.Close();
					req.Abort();
				}
				return mValidConnetion;
			}
			catch(Exception e)
			{
				return false;
			}
		}
		
		public bool GetDownloadBookList(String URL, ref List<DownloadableBook> books)
		{
			/* emulator debug test without network
			//for(int i = 0; i < 20; ++i )
			{
				DownloadableBook book;
				book.Name = "左傳.txt";
				book.URL = "http://FUCKYOU.COM/";
				book.Size = 0;
				book.State = BookState.NOLOCAL;
				books.Add(book);
				return true;
			}
			*/
			
			if( !mValidConnetion )
				return false;
			
			if( mScheme == Uri.UriSchemeFtp )
			{
				//TODO: ftp
				return false;
			}
			else if( mScheme == Uri.UriSchemeHttp )
			{
				try
				{
					//support HFS only
					
					HttpWebRequest req = (HttpWebRequest)WebRequest.Create(URL+"/~files.lst");
					//req.CachePolicy = new System.Net.Cache.RequestCachePolicy( System.Net.Cache.RequestCacheLevel.BypassCache );
					//req.Method = WebRequestMethods.Http.Post;
					//req.KeepAlive = true;
					
					//Console.WriteLine("GET: {0}",req.RequestUri.ToString() );
		        	HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
					if( resp.StatusCode != HttpStatusCode.OK )
						return false;
					//Console.WriteLine("AAA");
					Stream respStream = resp.GetResponseStream();
					//Console.WriteLine("stream");
					
					StreamReader reader = new StreamReader(respStream, Encoding.UTF8 );
					List<String> lines = new List<String>();
					while( !reader.EndOfStream )
					{
						 lines.Add( reader.ReadLine() );
					}
					respStream.Close();
					resp.Close();
					req.Abort();
					
					//Console.WriteLine("read");
					for(int i = 0; i < lines.Count; ++i)
					{
						DownloadableBook book;
						book.URL = lines[i];
						book.Name = Path.GetFileName( Uri.UnescapeDataString(book.URL) );
						//book.Name = this.UTF8ToUnicode(book.Name);
						//Console.WriteLine("日你");
						book.Size = 0;
											
						//Console.WriteLine(book.URL);
						//Console.WriteLine(book.Name);
						//Console.WriteLine(Path.GetExtension(book.Name));
						//skip none-text
						if( String.Compare( Path.GetExtension(book.Name),".txt",StringComparison.OrdinalIgnoreCase) != 0 )
							continue;
						
						#region get file size
						/*
						
						//get the file size
						//Console.WriteLine("{0}:{1}",WebRequestMethods.Http.Head,book.URL);
						HttpWebRequest size_req = (HttpWebRequest)WebRequest.Create(book.URL);
						//size_req.KeepAlive = true;
						//size_req.CachePolicy = new System.Net.Cache.RequestCachePolicy( System.Net.Cache.RequestCacheLevel.BypassCache );
						size_req.Method = WebRequestMethods.Http.Head;
						//size_req.Method = WebRequestMethods.Http.
						WebResponse size_resp = size_req.GetResponse();
						
						//Console.WriteLine(size_resp.ContentType);
						if( size_resp.ContentType != "text/plain" )
						{
							size_req.Abort();
							size_resp.Close();
							continue;
						}
						
						long size = size_resp.ContentLength;
						
						size_resp.Close();
						size_req.Abort();
						//Console.WriteLine(size);
						if( size >= 0 )
							book.Size = size;
						else
							continue;
						*/
						#endregion
						
						
						book.State = BookState.NOLOCAL;
						books.Add(book);
					}
					lines.Clear();
					return true;
				}
				catch(Exception e)
				{
					//Console.WriteLine(e.Message);
					return false;
				}
			}
			return false;
		}
		
		private String UTF8ToUnicode(String utf8String)
		{
	        Encoding unicode = Encoding.Unicode;
	        Encoding utf8 = Encoding.UTF8;
	        byte[] utf8Bytes = utf8.GetBytes(utf8String);
	        byte[] unicodeBytes = Encoding.Convert( utf8, unicode, utf8Bytes );
			return unicode.GetString(unicodeBytes);
		}
		
		public void StartDownload()
		{
			mDownloadState.Close();
			mDownloadIndex = -1;
		}
		
		public int UpdateDownloadBooks(String BookPath, ref List<DownloadableBook> list, ref List<DownloadItem> notifaction)
		{
			if(mDownloadIndex < list.Count )
			{
				//try download next file
				if( !mDownloadState.Downloading )
				{
					++mDownloadIndex;
					//Console.WriteLine("FUCK!{0}",mDownloadIndex);
					while( mDownloadIndex < list.Count )
					{
						DownloadableBook book = list[mDownloadIndex];
						DownloadItem item = notifaction[mDownloadIndex];
						if( book.State == BookState.UPDATED || !item.check.Checked)
						{
							//Console.WriteLine("skipping {0}",book.Name);
							++mDownloadIndex;
							continue;
						}
						else
							break;
					}
					
									//all finished
					if( mDownloadIndex >= list.Count )
						return mDownloadIndex;
					
					String Path = BookPath + '/' + list[mDownloadIndex].Name;
					notifaction[mDownloadIndex].StartDownload();
					mDownloadState.Open( list[mDownloadIndex].URL, Path);
				}

				//if(mDownloadState.Downloading )
				{
					//DownloadItem item = notifaction[i];
					const int CACHE_SIZE = 50*1024;//50K cache
					float progress = mDownloadState.Continue(CACHE_SIZE);				
					notifaction[mDownloadIndex].UpdateDownloadProgress(progress);
				}
				return mDownloadIndex;
			}
			return mDownloadIndex;
		}
		
	}//class
}